﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Xml;
using System.ComponentModel;

using System.Drawing;

namespace Prodcrast
{
    public class Feed
    {
        private DirectoryInfo m_DirectoryInfo = null;
        public DirectoryInfo DirectoryInfo
        {
            get { return m_DirectoryInfo; }
        }

        public bool NeedsRefresh { get; set; }
        
        private void NotifyPropertyChanged(string info)
        {
            NeedsRefresh = true;
        }

        private List<Episode> m_Episodes = new List<Episode>();
        public List<Episode> Episodes
        {
            get { return m_Episodes; }
        }

        private Image m_Icon = null;
        public Image Icon
        {
            get
            {
                if (m_Icon == null)
                    return Properties.Resources.feed;
                else
                    return m_Icon;
            }
            private set
            {
                m_Icon = value;
                NotifyPropertyChanged("Icon");
            }

        }

        public enum FeedState
        {
            Idle,
            Scanning
        }

        private FeedState m_State;
        public FeedState State
        {
            get
            {
                return m_State;
            }
            private set
            {
                m_State = value;
                NotifyPropertyChanged("State");
                NotifyPropertyChanged("StateIcon");
            }
        }

        public Image StateIcon
        {
            get
            {
                switch(State)
                {
                    case FeedState.Scanning:
                        return Properties.Resources.scanning_small;
                    default:
                        return Icon;
                }
            }
        }
        
        private string m_Name = "";
        public string Name {
            get
            {
                if (m_Name == "")
                    return FeedURL;
                else
                    return m_Name;
            }
            set {
                if (m_DirectoryInfo == null || !m_DirectoryInfo.Exists)
                {
                    m_DirectoryInfo = new DirectoryInfo(
                        Path.Combine(
                            Properties.Settings.Default.DownloadDirectory,
                            PathEx.Sanitize(value)
                        ));
                    if (!m_DirectoryInfo.Exists) m_DirectoryInfo.Create();
                }
                UpdateEpisodeDirectory();
                m_Name = value;
                NotifyPropertyChanged("Name");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void UpdateEpisodeDirectory()
        {
            foreach (Episode e in m_Episodes)
            {
                if(e.State == Episode.EpisodeState.Queued)
                    e.FindFile();
            }
        }

        public override string ToString()
        {
            return Name;
        }

        public string FeedURL { get; set; }

        /// <summary>
        /// Create new feed.
        /// </summary>
        /// <param name="URL"></param>
        public Feed(string URL)
        {
            FeedURL = URL;
        }

        /// <summary>
        /// Load a feed from XML.
        /// </summary>
        /// <param name="feedNode"></param>
        public Feed(XmlNode feedNode)
        {
            FeedURL = feedNode.Attributes["url"].Value;
            Name = feedNode.Attributes["name"].Value;

            foreach (XmlNode epNode in feedNode.ChildNodes)
            {
                if (epNode.Name == "episode")
                {
                    Episode e = new Episode(this, epNode);
                    m_Episodes.Add(e);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="parent"></param>
        public void SaveToXML(XmlDocument doc, XmlNode parent)
        {
            XmlElement feedNode = doc.CreateElement("feed");
            feedNode.SetAttribute("name", Name);
            feedNode.SetAttribute("url", FeedURL);

            foreach (Episode e in m_Episodes)
            {
                e.SaveToXML(doc, feedNode);
            }

            parent.AppendChild(feedNode);
        }

        /// <summary>
        /// 
        /// </summary>
        public void AbortAllDownloads()
        {
            foreach (Episode e in m_Episodes)
            {
                e.AbortDownload();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Scan()
        {
            if (State == FeedState.Idle)
            {
                State = FeedState.Scanning;

                WebRequest req = HttpWebRequest.Create(FeedURL);
                StreamReader stream = new StreamReader(req.GetResponse().GetResponseStream());

                XmlDocument xml = new XmlDocument();
                xml.LoadXml(stream.ReadToEnd());

                foreach (XmlNode n in xml.ChildNodes)
                {
                    if (n.Name == "rss")
                    {
                        Console.WriteLine("parsing rss");
                        foreach (XmlNode o in n.ChildNodes)
                        {
                            if (o.Name == "channel")
                            {
                                ParseChannel(o);
                            }
                        }
                    }
                }

                if(m_Icon == null)
                    FindIcon();

                State = FeedState.Idle;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void FindIcon()
        {
            try
            {
                Uri baseuri = new Uri(FeedURL);
                UriBuilder ub = new UriBuilder();
                ub.Host = baseuri.Host;
                ub.Path = "favicon.ico";

                WebRequest wr = WebRequest.Create(ub.Uri);
                Bitmap bmp = new Bitmap(wr.GetResponse().GetResponseStream());
                Icon = bmp;
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="channelNode"></param>
        private void ParseChannel(XmlNode channelNode)
        {
            Console.WriteLine("parsing channel");
            foreach (XmlNode node in channelNode.ChildNodes)
            {
                switch (node.Name)
                {
                    case "title":
                        if (m_Name == "")
                            Name = node.InnerText;
                        break;
                    case "item":
                        Episode e = Episode.CreateFromRSS(this, node);
                        if (!m_Episodes.Contains(e))
                            m_Episodes.Add(e);
                        break;
                    default:
                        Console.WriteLine("Ignored node {0}", node.Name);
                        break;
                }
            }

            if (m_Name == "")
                System.Diagnostics.Debugger.Break();
        }

        /// <summary>
        /// 
        /// </summary>
        public void DownloadAll()
        {
            List<Episode> sorted = new List<Episode>(
                m_Episodes.Where(
                    e => e.State == Episode.EpisodeState.Queued
                ));
            sorted.Sort(delegate(Episode l, Episode r)
            {
                return DateTime.Compare(l.Date, r.Date);
            });

            foreach (Episode e in sorted)
            {
                e.Download();
            }
        }
    }
}
